home *** CD-ROM | disk | FTP | other *** search
/ More MacCube 1: Arcade Games / More MacCube Vol 1 Arcade Games.bin / Games⁄Arcade / Bolo / More information / Sample Code / Std Autopilot / How to write plug-in brains < prev    next >
Encoding:
Text File  |  1995-05-10  |  14.5 KB  |  324 lines  |  [TEXT/KAHL]

  1. What are "Plug-In Brains?"
  2. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  3. Bolo supports plug-in 'brain' modules to drive Bolo tanks, to allow:
  4. 1. One player games against a number of 'AI' tanks.
  5. 2. Two player games, where each player commands a platoon of AI tanks.
  6. 3. 'Core War' style tournaments where people compete to write the best AI
  7.    algorithms.
  8.  
  9. Sample code is provided. It is basically the original Bolo 0.96 'Autopilot'
  10. converted to BBRN format, with the addition of better path finding and mine
  11. clearing. It is not very smart.
  12.  
  13. How to write plug-in 'brain' modules to drive Bolo tanks.
  14. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  15. Each plug-in brain module is a separate file, stored in the "Brains" folder.
  16.  
  17. The file should have type 'BBRN'.
  18. It can have any creator code, although 'BOLO' is probably a sensible choice.
  19. It should contain a CODE resource with ID 1000+x, where x is the BrainInfo
  20. version that your code is compiled for (see below). For version 3 of the
  21. interface, this means that you should make your code resource have ID 1003.
  22.  
  23. When the user selects your brain from the "Tank Control" menu in Bolo, your
  24. CODE resource is loaded into memory and locked down.
  25.  
  26. Your CODE resource will be called with A4 set to point to the base address
  27. of the resource (ie set up to support Think C's A4-relative CODE resource
  28. globals). You may make limited Operating System and Toolbox calls, including
  29. QuickDraw, if necessary (eg putting up a dialog box). (However, care must be
  30. taken if you decide to access QuickDraw globals. See the Think C manual
  31. chapter on CODE resources.) Your resource file will be open if you need
  32. access to your resources. One parameter is passed on the stack with pascal
  33. calling conventions. You should declare your main routine thus:
  34.  
  35. pascal short main(const BrainInfo *info)
  36.  
  37. The structure you are passed looks like this:
  38. typedef struct
  39.     {
  40.     u_short BoloVersion;    // two hex bytes, eg. 0x0098 means version 0.98
  41.     u_short InfoVersion;    // current version of the BrainInfo structure is 1
  42.     void   *userdata;        // Initially points to address of your CODE resource
  43.     u_short padding1;        // unused at present
  44.     u_short PrefsVRefNum;
  45.     u_char *PrefsFileName;
  46.     u_short operation;        // 0=OPEN, 1=CLOSE, 2=THINK, 200+ menu
  47.     u_short menu_item;
  48.     ... // (see accompanying header files for more details)
  49.     } BrainInfo;
  50.  
  51. BoloVersion is passed for informational value only. Most Brains should
  52. not care what version of Bolo is running. You should however check that
  53. InfoVersion indicates a version of the BrainInfo structure that your code
  54. understands. If your codes does not understand the InfoVersion then you
  55. should return a non-zero error code from the "OPEN" call.
  56.  
  57. "userdata" is provided for MPW users who do not have the A4-globals facility.
  58. It is initialized to point to the start address of your code (ie the same as
  59. the value in A4), but if you elect to change its value (say to point to a
  60. block of memory you have allocated for workspace) then that value will be
  61. preserved in subsequent calls. (You will have to use a cast to override the
  62. 'const' protection on the BrainInfo structure that Bolo passes to you --
  63. handle with care.)
  64.  
  65. PrefsVRefNum and PrefsFileName are passed so that you can access the user's
  66. Bolo Preferences file if you wish, to store settings between activations of
  67. your Brain. You should store your preferences as NAMED resources in the file.
  68.  
  69. A lot more information is passed in the BrainInfo structure, although most
  70. of it will only be relevant to the "THINK" call.
  71.  
  72. The operation codes.
  73. ~~~~~~~~~~~~~~~~~~~~
  74. 0: OPEN.
  75. The first call, made once, immediately after the CODE resource is loaded into
  76. memory. If you wish to offer user-configurability, you may add a menu to the
  77. menu bar. The menu ID should be 1000 or greater. If you need to use hierarchical
  78. sub-menus, you can use ids in the range 200-255. You may allocate memory for
  79. workspace, but your total memory usage (size of CODE resource plus size of
  80. extra memory allocated) must not exceed 32K. If you need more than this, you
  81. must use "MultiFinder Temporary Memory" (see Inside Macintosh VI 28-33).
  82. Return zero if initialization was successful, or non-zero if it failed
  83. (eg. insufficient memory). If non-zero is returned, your code will not be
  84. called again (not even a CLOSE message), so you must tidy up before returning.
  85.  
  86. 1: CLOSE.
  87. Called once as the final call when the user turns off your brain. You should
  88. ensure that all allocated memory is released, all menus are removed etc.
  89.  
  90. 2: THINK.
  91. This, the most important call, is done as frequently as the load on the
  92. Macintosh will allow. Each time, information describing the current start of
  93. the world around the tank is given, and your code should decide what action to
  94. take.
  95.  
  96. 200+: MENU.
  97. Called when the user chooses an item from your menu with this menu ID number.
  98. The number of the item which was selected from the menu is given in "menu_item".
  99.  
  100. The THINK message.
  101. ~~~~~~~~~~~~~~~~~~
  102. Every time through the main event loop, Bolo will send you a THINK message.
  103. This means that you are subject to the vagaries of the Macintosh process
  104. scheduling mechanism. If another application holds the CPU for a long time, or
  105. the user performs some action which hogs the machine, then it is possible that
  106. you might not get any calls for a significant length of time. You should be
  107. aware of this limitation, and users should be aware that if they overload the
  108. machine then AI routines will not perform very well. A corollary of this is
  109. that YOU can hog the CPU for a long time if you wish. However, Bolo is a real-
  110. time game. If you spend too long deciding what to do, then your tank will have
  111. been shot and destroyed by the time you make up your mind. A good guideline is
  112. no more than a tenth of a second of thinking time per call. If you want to be
  113. very ambitious and do dynamic adjustment, you can use TickCount or the Time
  114. Manager to measure the passage of time, and return when some suitable length
  115. of time has passed.
  116.  
  117. The information you are passed is basically a software interface to the
  118. information that a human player has available visually.
  119.  
  120. The maximum number of players is given because it controls the size of the
  121. player bitmap structures used for messages and alliances. It may also be
  122. useful to determine your memory allocation needs.
  123.  
  124. You are told your tank’s current position, speed, direction, whether it is
  125. on a boat etc.
  126. You are told your current tank stocks and other status information.
  127.  
  128. If newtank is non-zero it indicates that your tank was just killed, and this
  129. is new tank you are controlling. This is done so that your algorithm is not
  130. hopelessly confused to find itself suddenly on a boat out in the deep sea.
  131. Your first THINK message after the OPEN call will have this 'new tank'
  132. indication set.
  133.  
  134. If there is a friendly base within range, then its position and stocks are
  135. given. Otherwise base will be NULL.
  136.  
  137. If man_status is zero, the man is in the tank, ready for action. If man_status
  138. is one, then your man is dead and a new man is parachuting in. If man_status
  139. is any other value, then the man is outside the tank, building, in which case
  140. man_direction gives the direction of travel of the man, and (man_x, man_y)
  141. gives his current position.
  142.  
  143. If (*pillview) is non-negative, then the view you are given is centred on the
  144. pillbox with the given number. If (*pillview) is -1 then the view is centred on
  145. your tank. To change where your next view will come from, set (*pillview) to
  146. the desired value. You may attempt to view from a dead pillbox (or one you
  147. don't own) if you wish, but you will not see anything.
  148.  
  149. The array of TERRAIN squares is given as horizontal rows, from top to bottom,
  150. with the squares running left to right in each row (similar to the map file
  151. format). The map view information shows you everything within 14 squares of the
  152. tank -- ie anything a human could see by scrolling the tank view around with
  153. the cursor keys. For pillbox views, the visibility range is restricted to 7
  154. squares in every direction, as it is for humans.
  155. The bytes of the array have the values given below. The top bit of the byte
  156. will be set if the square has a mine (that you can see) on it.
  157.  
  158. typedef BYTE TERRAIN;
  159. enum
  160.     {
  161.     BUILDING=0, RIVER, SWAMP, CRATER, ROAD, FOREST, RUBBLE, GRASS,
  162.     HALFBUILDING, BOAT, DEEPSEA, REFBASE_T, PILLBOX_T,
  163.     NUM_TERRAINS,
  164.     TERRAIN_MASK = 0xF,
  165.     TERRAIN_MINE = 0x80,
  166.     };
  167.  
  168. For each object you can see, you are told its position, and some information.
  169. Your own tank is not included in the array of objects. All friendly pillboxes
  170. and bases are included in the array, even if currently beyond visual range.
  171.  
  172. typedef u_short OBJECT;
  173. enum
  174.     {
  175.     OBJECT_TANK=0,
  176.     OBJECT_SHOT,
  177.     OBJECT_PILLBOX,
  178.     OBJECT_REFBASE,
  179.     OBJECT_BUILDMAN,
  180.     OBJECT_PARACHUTE
  181.     };
  182. #define OBJECT_HOSTILE 1    // Object is hostile to us
  183. #define OBJECT_NEUTRAL 2    // Object is not loyal to any other player
  184. // Note that being neutral means that an object has no particular loyalty
  185. // to any player -- whether it is hostile or friendly to us is an orthogonal
  186. // question. Currently, neutral refuelling bases are friendly to everyone
  187. // and neutral pillboxes are hostile to everyone.
  188.  
  189. typedef struct
  190.     {
  191.     OBJECT object;
  192.     WORLD_X x;
  193.     WORLD_Y y;
  194.     WORD idnum;
  195.     BYTE direction;
  196.     BYTE info;
  197.     } ObjectInfo;
  198.  
  199. For tanks, pillboxes, refuelling bases, and men, an identifying number is
  200. given, which ranges from zero to the number of that kind of object minus one.
  201. One useful fact is that man number n is owned by tank number n.
  202.  
  203. For tanks and shots the approximate direction of travel is given.
  204. For pillboxes the 'direction' value gives the pillbox's current strength, in
  205. the range 0-15, as can be determined by human players looking at the graphics
  206. on the screen.
  207. For refuling bases, the 'direction' value will be zero if the base is dead
  208. and capturable, and non-zero otherwise. Unlike pillboxes, it does not tell
  209. you the exact strength of the base, only a rough approximation.
  210. For building men, the 'direction' value is unused.
  211.  
  212. Bit 0 of the info field (OBJECT_HOSTILE) is set if the object is hostile,
  213.       and clear if it is friendly.
  214. Bit 1 of the info field (OBJECT_NEUTRAL) is set if the object is neutral --
  215.       ie it is not currently 'owned' by any player.
  216.  
  217. MessageInfo structure
  218. ~~~~~~~~~~~~~~~~~~~~~
  219. If a message was sent to you then the MessageInfo pointer will be non-null, and
  220. will point to a MessageInfo structure as described below.
  221.  
  222. typedef struct
  223.     {
  224.     u_short sender;
  225.     PlayerMap *receivers;
  226.     u_char *message;
  227.     } MessageInfo;
  228.  
  229. The sender field tells you which player sent the message. You may examine
  230. playernames[sender] to find out the ASCII name of that player. The receivers
  231. field points to a bit map indicating which players the message was sent to, and
  232. the text of the message is given by the message field.
  233.  
  234. Controlling the tank
  235. ~~~~~~~~~~~~~~~~~~~~
  236. Macros are provided to set bits in the BoloKeyMap structure. Each bit
  237. corresponds to a tank control -- accelerate, decelerate, turn, shoot, etc.
  238. Setting a bit in the holdkeys structure is equivalent to the user holding that
  239. key down (until you clear the bit explicitly). Setting a bit in the tapkeys
  240. structure is equivalent to the user tapping the key briefly (for about 1/12th
  241. of a second). This can be useful for things like firing a single shot.
  242.  
  243. Building Control
  244. ~~~~~~~~~~~~~~~~
  245. typedef BYTE BUILDMODE;
  246. enum
  247.     {
  248.     BUILDMODE_FARM=1, BUILDMODE_ROAD,
  249.     BUILDMODE_BUILD, BUILDMODE_PBOX, BUILDMODE_MINE
  250.     };
  251.  
  252. typedef struct
  253.     {
  254.     MAP_X x;
  255.     MAP_Y y;
  256.     BUILDMODE action;
  257.     } BuildInfo;
  258.  
  259. If the action field is zero, you may set the x and y coordinates to the
  260. location you wish to build at, and set the action field to the operation
  261. you wish the man to perform. When the man has been dispatched from the
  262. tank to do the building, the action field will be reset to zero, and you
  263. may then queue up the next action, to be performed when the man returns.
  264.  
  265. Alliances
  266. ~~~~~~~~~
  267. The field "PlayerBitMap *allies" tells you who you are currently allied to.
  268. If you are not in any alliance, then the bit corresponding to yourself will
  269. always be set, indicating an 'alliance' of one player.
  270.  
  271. The field "PlayerBitMap *wantallies" is used to control alliance membership.
  272.  
  273. If you are currently in an alliance (of more than just yourself) then on
  274. each call, "wantallies" will be initialized to your current set of allies.
  275. You have three options:
  276.  
  277. 1. Leave it unchanged.
  278. 2. Set new bits, indicating alliance invitations to other players.
  279.    (The invited players must have already requested an alliance with you
  280.    for the invitation to take effect.)
  281. 3. Set it to zero, indicating your desire to leave this alliance.   
  282.  
  283. If you are NOT currently in an alliance, then the bits indicate who you would
  284. like to be in an alliance with, should they choose to invite you. You are free
  285. to set the bits any way you please, including all zero, to indicate that you
  286. do not want an alliance with anybody. It is not necessary to set the bit for
  287. yourself -- it is assumed that you want to be friendly to yourself.
  288.  
  289. If two non-allied players both indicate a desire to be allied to each other,
  290. then a mutual alliance is automatically formed.
  291.  
  292. Sending messages
  293. ~~~~~~~~~~~~~~~~
  294. messagedest points to a bitmap of flags as described above. For each tank you
  295. want to send to, set the appropriate bit in the bitmap. If sendmessage[0] is
  296. zero then you may write a message into the buffer it points to. The message
  297. should be a pascal string -- ie sendmessage[0] will then contain the length of
  298. the string. When the message has been sent, sendmessage[0] will be reset to
  299. zero. You can send a message to yourself only for the purpose of displaying
  300. debugging messages, if necessary.
  301.  
  302. A note on types
  303. ~~~~~~~~~~~~~~~
  304. Directions are given as single bytes, with the circle divided into 256
  305. divisions. 0 is North, 64 is East, 128 is South, 192 is West, and 255 is all
  306. the way around, almost back to due North.
  307.  
  308. MAP coordinates are 8 bits each for X and Y, and the unit is one map square.
  309. 0,0 is the top left corner of the 'world', and coordinates increase downwards
  310. and to the right. 255,255 is the bottom right corner of the world. The position
  311. of pillboxes and refueling bases are given in MAP coordinates, since they are
  312. constrained to lie on map squares.
  313.  
  314. WORLD coordinates are 16 bits each for X and Y. They are a higher resolution
  315. version of MAP coordinates, used for objects such as tanks which can move on a
  316. finer grid than whole map squares. Like MAP coordinates, WORLD coordinates
  317. start with 0,0 in the top left, increasing downwards and to the right. 256
  318. WORLD coordinate units make one MAP coordinate unit, so effectively the top
  319. byte of the WORLD coordinate gives the MAP square, and the low byte gives the
  320. location within the square.
  321.  
  322. The coordinates given for objects like tanks and shots give the position of the
  323. centre of the object.
  324.